package com.example.demo07cache.config;

import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class MultipleRedisConfig {

    /**
     * 连接池参数配置
     * yml 文件中的 lettuce 的 max-active 与 GenericObjectPoolConfig 的 maxTotal 是有冲突的，所以配置失效
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.redis.lettuce.pool")
    public GenericObjectPoolConfig poolConfig() {
        return new GenericObjectPoolConfig();
    }

    /**
     * Redis 连接配置
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.redis")
    public RedisStandaloneConfiguration redisConfig() {
        return new RedisStandaloneConfiguration();
        // 集群模式配置
//        return new RedisClusterConfiguration();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.redis1")
    public RedisStandaloneConfiguration redisConfig1() {
        return new RedisStandaloneConfiguration();
    }

    /**
     * ConnectionFactory 配置
     */
    @Bean
    @Primary
    public LettuceConnectionFactory factory(GenericObjectPoolConfig poolConfig, RedisStandaloneConfiguration redisConfig) {
        LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(poolConfig).build();
        return new LettuceConnectionFactory(redisConfig, clientConfiguration);
    }

    @Bean("factory1")
    public LettuceConnectionFactory factory1(GenericObjectPoolConfig poolConfig, RedisStandaloneConfiguration redisConfig1) {
        LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(poolConfig).build();
        return new LettuceConnectionFactory(redisConfig1, clientConfiguration);
    }

    /**
     * RedisTemplate 配置
     * Jackson 序列化必须要求对象有无参构造函数，否则无法进行序列化，而 FastJSON 没有这个要求
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // TODO: 如果保存对象，默认使用 jdk 序列化机制，序列化后的数据保存到 redis 中
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericFastJsonRedisSerializer());
        redisTemplate.setValueSerializer(new GenericFastJsonRedisSerializer());
        redisTemplate.setConnectionFactory(factory);
        // Jackson JSON 序列化
//        RedisSerializer.string();
//        RedisSerializer.json();
        return redisTemplate;
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate1(@Qualifier("factory1") RedisConnectionFactory factory1) {
        RedisTemplate<String, Object> redisTemplate5 = new RedisTemplate<>();
        redisTemplate5.setKeySerializer(new StringRedisSerializer());
        redisTemplate5.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate5.setHashValueSerializer(new GenericFastJsonRedisSerializer());
        redisTemplate5.setValueSerializer(new GenericFastJsonRedisSerializer());
        redisTemplate5.setConnectionFactory(factory1);
        return redisTemplate5;
    }

    @Bean
    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }

    @Bean
    public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForValue();
    }

    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForSet();
    }

    @Bean
    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForZSet();
    }

    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForList();
    }
}
